package com.suning.sawp.service.impl.dao;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.domain.Sort.Order;
import org.springframework.data.mongodb.core.MongoOperations;
import org.springframework.data.mongodb.core.mapreduce.MapReduceResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import com.suning.sawp.dto.promotion.HorizProCouponParam;
import com.suning.sawp.dto.promotion.StatisHorizCoupn;
import com.suning.sawp.dto.promotion.StatisticsHorCoupon;
import com.suning.sawp.intf.dao.HorizPromotionDaoService;
import com.suning.sawp.po.promotion.HorizProActivity;
import com.suning.sawp.po.promotion.HorizProCoupon;
import com.suning.sawp.po.promotion.HorizProRecord;
import com.suning.sawp.service.util.DJStringUtils;

@Service("horizPromotionDaoService")
public class HorizPromotionDaoServiceImpl implements HorizPromotionDaoService {

    @Resource
    MongoOperations mongoTemplate;
    
    @Resource
    MongoOperations safeMongoTemplate;
    
    @Override
    public HorizProActivity findHorizProActivityByActivityId(String activityId) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProActivity.Attributes.PRO_ACTIVITY_ID).is(activityId);
        query.addCriteria(criteria);
        
        return mongoTemplate.findOne(query, HorizProActivity.class);
    }

    @Override
    public void addHorizProActivity(HorizProActivity horizProActivity) {
        mongoTemplate.insert(horizProActivity);
    }

    @Override
    public List<HorizProActivity> findActivity4Page(String activityName, String proActivityId, Date startTime,
            Date endTime, int startIndex, int limit) {
        // 初始化db查询参数
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (StringUtils.isNotBlank(activityName)){
            criteria.and(HorizProActivity.Attributes.ACTIVITY_NAME).regex(activityName);
        }
        if (StringUtils.isNotBlank(proActivityId)){
            criteria.and(HorizProActivity.Attributes.PRO_ACTIVITY_ID).is(proActivityId);
        }
        if (null != startTime){
            criteria.and(HorizProActivity.Attributes.STARTTIME).gte(startTime);
        }
        if (null != endTime){
            criteria.and(HorizProActivity.Attributes.ENDTIME).lte(endTime);
        }
        query.addCriteria(criteria);
        // 分页参数
        query.skip(startIndex);
        query.limit(limit);
        
        List<HorizProActivity> horiActList = mongoTemplate.find(query, HorizProActivity.class);
        return horiActList;
    }

    @Override
    public void updateActivityActualActCount(String staffId, String proActivityId, int importCount) {
        Query queryHoriz = new Query();
        Criteria criteriaHoriz = new Criteria();
        criteriaHoriz.and(HorizProActivity.Attributes.PRO_ACTIVITY_ID).is(proActivityId);
        queryHoriz.addCriteria(criteriaHoriz);
        Update update = new Update();
        update.set(HorizProActivity.Attributes.UPDATOR, staffId);
        update.set(HorizProActivity.Attributes.UPDATE_TIME, new Date());
        update.inc(HorizProActivity.Attributes.ACTUAL_ACT_COUNT, importCount);
        mongoTemplate.updateFirst(queryHoriz, update, HorizProActivity.class);
    }

    @Override
    public int deleteHorizCouponByimpBatchCd(String importBatch){
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProCoupon.Attributes.IMPORT_BATCH).is(importBatch);
        query.addCriteria(criteria);
        int total = (int) safeMongoTemplate.count(query, HorizProCoupon.class);
        safeMongoTemplate.remove(query, HorizProCoupon.class);
        return total;
    }

    @Override
    public List<HorizProRecord> findHorizProRecords(String activityId,
            String staffId, int startIndex, int limit) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProRecord.Attributes.ACTIVITY_ID).is(activityId);
        if (StringUtils.isNotBlank(staffId)) {
            criteria.and(HorizProRecord.Attributes.OPERATOR).is(staffId);
        }
        query.addCriteria(criteria);
        query.with(new Sort(new Order(Direction.DESC, HorizProRecord.Attributes.OPERATOR_TIME)));
        query.skip(startIndex).limit(limit);
        
        return mongoTemplate.find(query, HorizProRecord.class);
    }

    @Override
    public void updateActivityStatus(String activityId, String optCode, String staffId) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProActivity.Attributes.PRO_ACTIVITY_ID).is(activityId);
        query.addCriteria(criteria);
        Update update = new Update();
        update.set(HorizProActivity.Attributes.UPDATOR, staffId);
        update.set(HorizProActivity.Attributes.UPDATE_TIME, new Date());
        update.set(HorizProActivity.Attributes.IS_USED, optCode);
        mongoTemplate.updateFirst(query, update, HorizProActivity.class);
    }
    
    @Override
    public HorizProCoupon queryHorizCouponByHorId(String horizId){
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProCoupon.Attributes.HORIZID).is(horizId);
        query.addCriteria(criteria);
        return mongoTemplate.findOne(query, HorizProCoupon.class);
    }
    
    @Override
    public void updateHorizProCoupon(HorizProCouponParam couponParam){
        //更新异业优惠券记录表
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProCoupon.Attributes.HORIZID).is(couponParam.getHorizId());
        query.addCriteria(criteria);
        Update update = new Update();
        update.set("custNum", couponParam.getCustNum());
        update.set("mobile", couponParam.getMobile());
        update.set("staffId", couponParam.getStaffId());
        update.set("valiCouponTime", new Date());
        update.set("regionCode", couponParam.getRegionCode());
        update.set("regionName", couponParam.getRegionName());
        update.set("storeCode", couponParam.getStoreCode());
        update.set("storeName", couponParam.getStoreName());
        mongoTemplate.updateFirst(query, update, HorizProCoupon.class);
    }

    @Override
    public void incrActivityHasSend(String activityId) {
        Query queryHorAct = new Query();
        Criteria criteriaHorAct = new Criteria();
        criteriaHorAct.and(HorizProActivity.Attributes.PRO_ACTIVITY_ID).is(activityId);
        queryHorAct.addCriteria(criteriaHorAct);
        Update update = new Update();
        update.inc(HorizProActivity.Attributes.HAS_SEND, 1);
        mongoTemplate.updateFirst(queryHorAct, update, HorizProActivity.class);
    }

    @Override
    public int countHorizProCouponByStaffId(String staffId) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProCoupon.Attributes.STAFF_ID).is(staffId);
        query.addCriteria(criteria);
        int totalSize = (int) mongoTemplate.count(query, HorizProCoupon.class);
        return totalSize;
    }

    @Override
    public List<HorizProCoupon> findHorizProCouponsByStaffId(String staffId, int startIndex, int limit) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProCoupon.Attributes.STAFF_ID).is(staffId);
        query.addCriteria(criteria);
        // 根据验证时间倒序
        query.with(new Sort(new Order(Direction.DESC, HorizProCoupon.Attributes.VALI_COUPON_TIME)));
        // 查询分页数据
        query.skip(startIndex).limit(limit);
        List<HorizProCoupon> list = mongoTemplate.find(query, HorizProCoupon.class);
        return list;
    }

    @Override
    public int countHorizProActivity(String activityName, String proActivityId, Date startTime, Date endTime) {
     // 初始化db查询参数
        Query query = new Query();
        Criteria criteria = new Criteria();
        if (StringUtils.isNotBlank(activityName)){
            criteria.and(HorizProActivity.Attributes.ACTIVITY_NAME).regex(activityName);
        }
        if (StringUtils.isNotBlank(proActivityId)){
            criteria.and(HorizProActivity.Attributes.PRO_ACTIVITY_ID).is(proActivityId);
        }
        if (null != startTime){
            criteria.and(HorizProActivity.Attributes.STARTTIME).gte(startTime);
        }
        if (null != endTime){
            criteria.and(HorizProActivity.Attributes.ENDTIME).lte(endTime);
        }
        query.addCriteria(criteria);
        
        int totalSize = (int) mongoTemplate.count(query, HorizProActivity.class);
        return totalSize;
    }

    @Override
    public int countHorizProRecord(String activityId, String staffId) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProRecord.Attributes.ACTIVITY_ID).is(activityId);
        if (StringUtils.isNotBlank(staffId)) {
            criteria.and(HorizProRecord.Attributes.OPERATOR).is(staffId);
        }
        query.addCriteria(criteria);
        
        int totalSize = (int) mongoTemplate.count(query, HorizProRecord.class);
        return totalSize;
    }

    @Override
    public void deleteHorizRecordByImportBatch(String importBacth) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProRecord.Attributes.IMPORT_BATCH).is(importBacth);
        query.addCriteria(criteria);
        
        mongoTemplate.remove(query, HorizProRecord.class);
    }

    @Override
    public int countValidHorizCoupon(Date startTime, Date endTime) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProCoupon.Attributes.VALI_COUPON_TIME)
            .gte(startTime).lte(endTime).and(HorizProCoupon.Attributes.CUST_NUM).exists(true);
        query.addCriteria(criteria);
        
        int totalSize = (int) mongoTemplate.count(query, HorizProCoupon.class);
        return totalSize;
    }

    @Override
    public List<HorizProCoupon> findValidHorizProCoupons(Date startTime, Date endTime) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProCoupon.Attributes.VALI_COUPON_TIME)
            .gte(startTime).lte(endTime).and(HorizProCoupon.Attributes.CUST_NUM).exists(true);
        query.addCriteria(criteria);
        
        return mongoTemplate.find(query, HorizProCoupon.class);
    }
    
    @Override
    public void updateActivityCouponFileUrl(String activityId, String fileUrl, Integer actualActCount) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        criteria.and(HorizProActivity.Attributes.PRO_ACTIVITY_ID).is(activityId);
        query.addCriteria(criteria);
        Update update = new Update();
        update.set(HorizProActivity.Attributes.COUPON_FILE_URL, fileUrl);
        update.set(HorizProActivity.Attributes.UPDATE_TIME, new Date());
        update.set(HorizProActivity.Attributes.ACTUAL_ACT_COUNT, actualActCount);
        mongoTemplate.updateFirst(query, update, HorizProActivity.class);
    }

    @SuppressWarnings("rawtypes")
    @Override
    public int countStatisHorizCoupon(String activityName, String regionCode, String storeCode,
            Date startTime, Date endTime) {
        Query query = new Query();
        Criteria criteria = new Criteria();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(endTime);
        calendar.add(Calendar.DATE, 1);
        criteria.and(HorizProCoupon.Attributes.VALI_COUPON_TIME)
            .gte(startTime).lte(calendar.getTime());
        if(StringUtils.isNotBlank(activityName)){
            criteria.and(HorizProCoupon.Attributes.ACTIVITY_NAME).regex(DJStringUtils.escapeExprSpecialWord(activityName));
        }
        if(StringUtils.isNotBlank(regionCode)){
            criteria.and(HorizProCoupon.Attributes.REGION_CODE).is(regionCode);
        }
        if(StringUtils.isNotBlank(storeCode)){
            criteria.and(HorizProCoupon.Attributes.STORE_CODE).is(storeCode);
        }else{
            criteria.and(HorizProCoupon.Attributes.STORE_CODE).exists(true);
        }
        query.addCriteria(criteria);
        List list = mongoTemplate.getCollection("HorizProCoupon").distinct(HorizProCoupon.Attributes.STORE_CODE, query.getQueryObject());
        return list == null ? 0 :list.size();
    }
    
    @Override
    public List<StatisticsHorCoupon> statisHorizCoupon(String activityName, String regionCode,
            String storeCode, Date startTime, Date endTime, Integer startIndex, Integer limit) {
        List<StatisticsHorCoupon> list = new ArrayList<StatisticsHorCoupon>();
        Query query = new Query();
        Criteria criteria = new Criteria();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(endTime);
        calendar.add(Calendar.DATE, 1);
        criteria.and(HorizProCoupon.Attributes.VALI_COUPON_TIME)
            .gte(startTime).lte(calendar.getTime());
        if(StringUtils.isNotBlank(activityName)){
            criteria.and(HorizProCoupon.Attributes.ACTIVITY_NAME).regex(DJStringUtils.escapeExprSpecialWord(activityName));
        }
        if(StringUtils.isNotBlank(regionCode)){
            criteria.and(HorizProCoupon.Attributes.REGION_CODE).is(regionCode);
        }
        if(StringUtils.isNotBlank(storeCode)){
            criteria.and(HorizProCoupon.Attributes.STORE_CODE).is(storeCode);
        }else{
            criteria.and(HorizProCoupon.Attributes.STORE_CODE).exists(true);
        }
        query.addCriteria(criteria);
        /**query.skip(startIndex).limit(limit);**/
        String mapFunc = "function(){emit(this.storeCode+this.proActivityId, {activityName:this.proActivityName,regionName:this.regionName,storeName:this.storeName,couponAmount:1});}";
        String reduceFunc = "function (key, value) {var result = {activityName:'',regionName:'',storeName:'',couponAmount:0};"+
        "for  ( var  i=0;i<value.length;i++) {"+
        "result.activityName= value[i].activityName;"+
        "result.regionName= value[i].regionName;"+
        "result.storeName= value[i].storeName;"+
        "result.couponAmount += value[i].couponAmount;"+
        "}"+
        "return result;}";
        MapReduceResults<StatisHorizCoupn> mapReduce = mongoTemplate.mapReduce(query,"HorizProCoupon",mapFunc, reduceFunc,StatisHorizCoupn.class);
        if(mapReduce != null){
            for(StatisHorizCoupn coupon : mapReduce){
               list.add(coupon.getValue());
            }
        }
        return list;
    }
}
